﻿#include "wtcpclient.h"
#include "cmainframe.h"
#include "common.h"
#include "NedAllocatorImpl.h"
#include "fastlz.h"

initialiseSingleton(WTcpClient);

wxDEFINE_EVENT(wxEVT_TCP_CLIENT_DATA_RECEIVED, wxCommandEvent);

wxBEGIN_EVENT_TABLE(WTcpClient, wxEvtHandler)
    EVT_SOCKET(wxID_ANY, WTcpClient::OnSocketEvent)
wxEND_EVENT_TABLE()

WTcpClient::WTcpClient(wxEvtHandler* parent)
    : m_parent(parent), m_socket(nullptr),
      m_NetworkFrameManager(NULL),
      isProcessMsgHearder(false),
      errorCount(0),
      m_enableReconnect(true),
      m_serverPort(0)
{
    InitSocket();

    m_HeartTimeOutTimer = new wxTimer(this, wxID_ANY);
    this->Bind(wxEVT_TIMER, &WTcpClient::OnHeartTimeOutTimer,
               this,m_HeartTimeOutTimer->GetId());
    m_reconnectTimer = new wxTimer(this,wxID_ANY+1);
    this->Bind(wxEVT_TIMER, &WTcpClient::OnReconnectTimer,
               this,m_reconnectTimer->GetId());
}

WTcpClient::~WTcpClient()
{
    this->disconnect();

    Disconnect();
    wxDELETE(m_socket);
}

void WTcpClient::InitSocket()
{
    if (m_socket)
    {
        m_socket->Destroy();
        wxDELETE(m_socket);
    }

    m_socket = new wxSocketClient(wxSOCKET_NOWAIT);
    m_socket->SetEventHandler(*this);
    m_socket->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
    m_socket->Notify(true);
}

bool WTcpClient::connect(wxString host, unsigned short port)
{
    if (isConnected())
    {
        Disconnect();
    }

    m_serverIP = host;
    m_serverPort = port;

    wxIPV4address addr;
    addr.Hostname(host);
    addr.Service(port);

    m_socket->Connect(addr, false);

    // 等待连接建立
    m_socket->WaitOnConnect(10); // 10秒超时

    CMainFrame::getSingleton().printlog(LOG_LEVEL_INFO,
                                        wxString::Format(wxT("正在连接服务器:%s:%d"),host,port).ToUTF8().data());

    return m_socket->IsConnected();
}

void WTcpClient::disconnect()
{
    if (m_socket && m_socket->IsConnected())
    {
        m_socket->Close();
    }

    if(m_HeartTimeOutTimer)
        m_HeartTimeOutTimer->Stop();

    if(m_reconnectTimer)
        m_reconnectTimer->Stop();

    memset(&mMsgHearder,0,sizeof(tagMsgHearder));
    isProcessMsgHearder=false;
    errorCount=0;
    m_buffer.Clear();
}

bool WTcpClient::isConnected() const
{
    return m_socket && m_socket->IsConnected();
}

bool WTcpClient::Send(wxString data)
{
    if (!isConnected())
        return false;

    const std::string buffer = data.ToStdString();
    return Send(buffer.c_str(), buffer.length());
}

bool WTcpClient::SendData(int msgtype,const void* data,size_t len)
{
    if (!isConnected())
        return false;

    tagMsgHearder decMsgHearder;
    memset(&decMsgHearder,0,sizeof(tagMsgHearder));
    decMsgHearder.msgType = msgtype;
    decMsgHearder.mark[0] = 'M';
    decMsgHearder.mark[1] = 'O';
    decMsgHearder.mark[2] = 'N';

    if(data == NULL || len <= 0)
    {
        this->Send(&decMsgHearder,sizeof(tagMsgHearder));
        return true;
    }

    decMsgHearder.checknum = qChecksum((const char*)data,len);
    decMsgHearder.srcLength = len;

    wxMemoryBuffer comBuffer = CompressWithFastLZ(data,len);
    decMsgHearder.compLength = comBuffer.GetDataLen();

    this->Send(&decMsgHearder,sizeof(tagMsgHearder));
    this->Send(comBuffer.GetData(),comBuffer.GetDataLen());

    return true;
}

bool WTcpClient::Send(const void* data, size_t len)
{
    if (!isConnected())
        return false;

    int curSendPos = 0;

    while(curSendPos < len)
    {
        m_socket->Write((const char*)data+curSendPos, len-curSendPos);

        if (m_socket->LastError() != wxSOCKET_NOERROR)
            return false;

        curSendPos += m_socket->LastCount();
    }

    return true;
}

void WTcpClient::OnSocketEvent(wxSocketEvent& event)
{
    switch (event.GetSocketEvent())
    {
    case wxSOCKET_INPUT:
        ReadData();
        break;
    case wxSOCKET_LOST:
    {
        CMainFrame::getSingleton().printlog(LOG_LEVEL_INFO,"与服务器断开连接.");
        if(m_NetworkFrameManager)
            m_NetworkFrameManager->OnTcpClientProcessDisconnectedNet(this);

        // 5秒后重连
        if(m_enableReconnect && m_reconnectTimer)
        {
            CMainFrame::getSingleton().printlog(LOG_LEVEL_INFO,"5秒后将重新连接服务器.");
            m_reconnectTimer->Start(5000);
        }

        this->Disconnect();
    }
        break;
    case wxSOCKET_CONNECTION:
    {
        CMainFrame::getSingleton().printlog(LOG_LEVEL_INFO,"与服务器连接成功.");

        if(m_reconnectTimer)
            m_reconnectTimer->Stop();

        if(m_HeartTimeOutTimer)
            m_HeartTimeOutTimer->Start(2000); // 2秒

        if(m_NetworkFrameManager)
            m_NetworkFrameManager->OnTcpClientProcessConnectedNet(this);
    }
        break;
    default:
        break;
    }
}

void WTcpClient::ReadData()
{
    if (!m_socket || !m_socket->IsConnected())
        return;

    // 读取所有可用数据
    while (m_socket->IsData())
    {
        char buffer[4096];
        m_socket->Read(buffer, sizeof(buffer));
        size_t bytesRead = m_socket->LastCount();

        if (bytesRead > 0)
        {
            if(m_buffer.GetBufSize()+bytesRead > m_buffer.GetBufSize())
                m_buffer.SetBufSize(m_buffer.GetBufSize()+bytesRead);

            m_buffer.AppendData(buffer,bytesRead);
        }
    }

    while(!m_buffer.IsEmpty())
    {
        // 先处理消息头
        if(m_buffer.GetDataLen() >= sizeof(tagMsgHearder) &&
           this->isProcessMsgHearder == false)
        {
            memcpy(&this->mMsgHearder,m_buffer.GetData(),sizeof(tagMsgHearder));
            RemoveDataFromMemoryBuffer(m_buffer,0,sizeof(tagMsgHearder));

            if(this->mMsgHearder.mark[0] != 'M' ||
               this->mMsgHearder.mark[1] != 'O' ||
               this->mMsgHearder.mark[2] != 'N')
            {
                if(this->errorCount++ > 5)
                {
                    Disconnect();
                    return;
                }

                continue;
            }

            this->isProcessMsgHearder=true;
        }

        if(!this->isProcessMsgHearder ||
           (this->isProcessMsgHearder &&
            m_buffer.GetDataLen() < this->mMsgHearder.compLength))
            return;

        wxMemoryBuffer srcDataBuffer = DecompressWithFastLZ(m_buffer.GetData(),
                                                            this->mMsgHearder.compLength,
                                                            this->mMsgHearder.srcLength);
        RemoveDataFromMemoryBuffer(m_buffer,0,this->mMsgHearder.compLength);
        this->isProcessMsgHearder = false;
        this->errorCount = 0;

        if((srcDataBuffer.IsEmpty() && this->mMsgHearder.msgType == IDD_NETWORK_MSG_HEART) ||
           qChecksum((const char*)srcDataBuffer.GetData(),srcDataBuffer.GetDataLen()) != this->mMsgHearder.checknum)
        {
            continue;
        }

        // 网络框架处理json消息
        if(m_NetworkFrameManager)
            m_NetworkFrameManager->OnTcpClientProcessNetData(this,
                                                    this->mMsgHearder.msgType,
                                                    srcDataBuffer);
    }
}

void WTcpClient::OnReconnectTimer(wxTimerEvent& event)
{
    this->connect(this->m_serverIP,this->m_serverPort);
}

void WTcpClient::OnHeartTimeOutTimer(wxTimerEvent& event)
{
    this->SendData(IDD_NETWORK_MSG_HEART,NULL,0);
}
